package com.hzh.page.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzh.page.common.enums.AuditEnum;
import com.hzh.page.common.enums.PublishStatusEnum;
import com.hzh.page.common.enums.RoleEnum;
import com.hzh.page.common.exception.Assert;
import com.hzh.page.common.exception.ResponseEnum;
import com.hzh.page.common.utils.JwtUtils;
import com.hzh.page.dao.PageInfoMapper;
import com.hzh.page.pojo.*;
import com.hzh.page.service.*;
import com.hzh.page.vo.PageInfoReqVO;
import com.hzh.page.vo.PageInfoRespVO;
import com.hzh.page.vo.PageNumVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author HZH
 * @since 2022-11-11
 */
@Slf4j
@Service
public class PageInfoServiceImpl extends ServiceImpl<PageInfoMapper, PageInfo> implements PageInfoService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Resource
    private AuthenticationUserService userService;
    @Resource
    private RegionService regionService;
    @Resource
    private AuthenticationUserRoleService userRoleService;
    @Resource
    private PageCategoryService pageCategoryService;
    @Resource
    private AuthenticationRoleService roleService;


    @Override
    public Page<PageInfoRespVO> queryPageList(Page<PageInfo> pageParam, PageInfoReqVO pageInfoReqVO) {
        Map<Integer, String> roleMap = null;
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String roles = ops.get("roleMap");

        if (StringUtils.isEmpty(roles)) {
            roleMap = roleService.list().stream().collect(Collectors.toMap(AuthenticationRoleEntity::getId, AuthenticationRoleEntity::getRoleName));
            ops.setIfAbsent("roleMap", JSON.toJSONString(roleMap), 1, TimeUnit.DAYS);
        } else {
            log.info("redis缓存命中roleMap");
            roleMap = JSON.parseObject(roles, new TypeReference<Map<Integer, String>>() {
            });
        }
        String categoryListFromRedis = ops.get("categoryList");
        List<PageCategory> categoryList;
        if (!StringUtils.isEmpty(categoryListFromRedis)) {
            log.info("redis缓存命中categoryList");
            categoryList = JSON.parseObject(categoryListFromRedis, new TypeReference<List<PageCategory>>() {
            });
        } else {
            categoryList = pageCategoryService.list();
            ops.setIfAbsent("categoryList", JSON.toJSONString(categoryList), 1, TimeUnit.DAYS);
        }

        Map<Long, String> categoryMap = categoryList.stream().collect(Collectors.toMap(PageCategory::getCategoryId, PageCategory::getValue));
        QueryWrapper<PageInfo> queryWrapper = new QueryWrapper<>();
        //"文章信息列表 -- 分页查询 -- 条件查询(标题，作者名，发布状态，审核状态，文章类别)"
        if (pageInfoReqVO.getPageId() != null) {
            queryWrapper.eq("page_id", pageInfoReqVO.getPageId());
        }
        if (!StringUtils.isEmpty(pageInfoReqVO.getUserName())) {
            AuthenticationUser user = userService.getOne(new QueryWrapper<AuthenticationUser>().eq("user_name", pageInfoReqVO.getUserName()));
            Assert.notNull(user, ResponseEnum.LOGIN_USER_NOEXIST);
            queryWrapper.eq("author_id", user.getId());
        }
        if (pageInfoReqVO.getAuthorId() != null) {
            queryWrapper.eq("author_id", pageInfoReqVO.getAuthorId());
        }
        if (!CollectionUtils.isEmpty(pageInfoReqVO.getPublishStateList())) {
            queryWrapper.in("publish_state",pageInfoReqVO.getPublishStateList());
        }
        if (pageInfoReqVO.getPublishState() != null) {
            queryWrapper.eq("publish_state", pageInfoReqVO.getPublishState());
        }
        if (!StringUtils.isEmpty(pageInfoReqVO.getTitle())) {
            queryWrapper.like("title", pageInfoReqVO.getTitle());
        }
        if (!CollectionUtils.isEmpty(pageInfoReqVO.getAuditStateList())) {
            queryWrapper.in("audit_state",pageInfoReqVO.getAuditStateList());
        }
        if (pageInfoReqVO.getAuditState() != null) {
            queryWrapper.eq("audit_state", pageInfoReqVO.getAuditState());
        }
        if (pageInfoReqVO.getCategoryId() != null) {
            queryWrapper.eq("category_id", pageInfoReqVO.getCategoryId());
        }
        Page<PageInfo> pageInfoList = baseMapper.selectPage(pageParam, queryWrapper);
        if (!StringUtils.isEmpty(pageInfoReqVO.getUserName()) || pageInfoReqVO.getUserId() != null) {
            AuthenticationUser user = null;
            if (pageInfoReqVO.getUserId() == null) {
                user = userService.getOne(new QueryWrapper<AuthenticationUser>().eq("user_name", pageInfoReqVO.getUserName()));
                Assert.notNull(user, ResponseEnum.LOGIN_USER_NOEXIST);
            } else {
                user = userService.getById(pageInfoReqVO.getUserId());
                Assert.notNull(user, ResponseEnum.LOGIN_USER_NOEXIST);
            }
            AuthenticationUserRoleEntity roleEntity = userRoleService.getOne(new QueryWrapper<AuthenticationUserRoleEntity>().eq("user_id", user.getId()));
            RegionEntity region = regionService.getById(user.getRegionId());
            AuthenticationUser finalUser = user;
            Map<Integer, String> finalRoleMap = roleMap;
            List<PageInfoRespVO> list = pageInfoList.getRecords().stream().map(pageInfo -> {
                PageInfoRespVO pageInfoRespVO = new PageInfoRespVO();
                BeanUtils.copyProperties(pageInfo, pageInfoRespVO);
                pageInfoRespVO.setRegion(region.getValue());
                pageInfoRespVO.setAuthor(finalUser.getUserName());
                pageInfoRespVO.setRoleId(roleEntity.getRoleId());
                pageInfoRespVO.setRoleName(finalRoleMap.get(roleEntity.getRoleId()));
                pageInfoRespVO.setCategoryName(categoryMap.get(pageInfoRespVO.getCategoryId()));
                return pageInfoRespVO;
            }).collect(Collectors.toList());
            Page<PageInfoRespVO> respVoPage = new Page<>();
            BeanUtils.copyProperties(pageInfoList, respVoPage);
            return respVoPage.setRecords(list);
        } else {
            return pageInfoToPageInfoVO(pageInfoList);
        }
    }


    /**
     * 将PageInfo封装成PageInfoVO
     */
    public Page<PageInfoRespVO> pageInfoToPageInfoVO(Page<PageInfo> pageInfoList) {
        Map<Integer, String> roleMap;
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String roles = ops.get("roleList");

        if (StringUtils.isEmpty(roles)) {
            roleMap = roleService.list().stream().collect(Collectors.toMap(AuthenticationRoleEntity::getId, AuthenticationRoleEntity::getRoleName));
            ops.setIfAbsent("roleMap", JSON.toJSONString(roleMap), 1, TimeUnit.DAYS);
        } else {
            roleMap = JSON.parseObject(roles, new TypeReference<Map<Integer, String>>() {
            });
        }


        Map<Integer, String> finalRoleMap = roleMap;
        String regionListFromRedis = ops.get("regionList");
        List<RegionEntity> regionList;
        if (!StringUtils.isEmpty(regionListFromRedis)) {
            log.info("缓存命中:regionList");
            regionList = JSON.parseObject(regionListFromRedis, new TypeReference<List<RegionEntity>>() {
            });
        } else {
            regionList = regionService.list();
            ops.set("regionList", JSON.toJSONString(regionList));
        }

        String categoryListFormRedis = ops.get("categoryList");
        List<PageCategory> categoryList;
        if (!StringUtils.isEmpty(categoryListFormRedis)) {
            log.info("缓存命中:categoryList");
            categoryList = JSON.parseObject(categoryListFormRedis, new TypeReference<List<PageCategory>>() {
            });
        } else {
            categoryList = pageCategoryService.list();
            ops.set("regionList", JSON.toJSONString(regionList));
        }

        Map<Long, String> categoryMap = categoryList.stream().collect(Collectors.toMap(PageCategory::getCategoryId, PageCategory::getValue));
        List<PageInfoRespVO> list = pageInfoList.getRecords().stream().map(pageInfo -> {
            PageInfoRespVO pageInfoRespVO = new PageInfoRespVO();
            BeanUtils.copyProperties(pageInfo, pageInfoRespVO);
            AuthenticationUser user = userService.getById(pageInfo.getAuthorId());
            if (user == null) { //作者信息为直接将作者信息置空
                return pageInfoRespVO;
            }
            for (RegionEntity regionEntity : regionList) {
                if (regionEntity.getId().equals(user.getRegionId())) {
                    pageInfoRespVO.setRegion(regionEntity.getValue());
                }
            }
            Integer roleId = userRoleService.getOne(new QueryWrapper<AuthenticationUserRoleEntity>().eq("user_id", user.getId())).getRoleId();
            pageInfoRespVO.setAuthor(user.getUserName());
            pageInfoRespVO.setRoleId(roleId);
            pageInfoRespVO.setCategoryName(categoryMap.get(pageInfoRespVO.getCategoryId()));
            pageInfoRespVO.setRoleName(finalRoleMap.get(roleId));
            return pageInfoRespVO;
        }).collect(Collectors.toList());
        Page<PageInfoRespVO> respVoPage = new Page<>();
        BeanUtils.copyProperties(pageInfoList, respVoPage);
        return respVoPage.setRecords(list);
    }

    /**
     * 新增文章
     */
    @Override
    public void addOrUpdatePage(PageInfo pageInfo) {
        if (pageInfo.getPageId() == null){
            baseMapper.insert(pageInfo);
        }else {
            baseMapper.updateById(pageInfo);
        }

    }



    @Override
    public Page<PageInfoRespVO> getNoAuditPageList(Page<PageInfo> pageParam, HttpServletRequest request) {
        String token = request.getHeader("token");
        Integer userId = JwtUtils.getUserId(token);

        AuthenticationUserRoleEntity userRoleInfo = userRoleService.getOne(new QueryWrapper<AuthenticationUserRoleEntity>().eq("user_id", userId));
        if (userRoleInfo.getRoleId().equals(RoleEnum.SUPER_ADMIN_ROLE.getId())) {
            //当前用户为超级管理员，查看所有未审核的文章
            Page<PageInfo> pageInfoList = baseMapper.selectPage(pageParam, new QueryWrapper<PageInfo>().eq("audit_state", AuditEnum.SUPER_ADMIN_ROLE.getAuditState())
                    .eq("publish_state", 0));
            return pageInfoToPageInfoVO(pageInfoList);
        }else if (userRoleInfo.getRoleId().equals(RoleEnum.ADMIN_ROLE.getId())){
            //当前用户为区域管理员，查看所管理的区域的文章未审核的文章
            int pageSize = (int) pageParam.getSize();
            int pageNum = (int) (pageParam.getCurrent()-1) * pageSize;
            Integer totalCount = baseMapper.getRegionAdminNoAuditPageListTotalCount(userId);
            List<PageInfo> pageInfoList = baseMapper.getRegionAdminNoAuditPageList(userId, pageNum, pageSize);
            Page<PageInfo> pageInfoPage = new Page<>();
            pageInfoPage.setRecords(pageInfoList);
            pageInfoPage.setTotal(totalCount);
            pageInfoPage.setCurrent(pageParam.getCurrent());
            return pageInfoToPageInfoVO(pageInfoPage);
        }else {
            //仅查看当前用户自己的未审核的文章
            Page<PageInfo> pageInfoPage = baseMapper.selectPage(pageParam, new QueryWrapper<PageInfo>().eq("author_id", userId));
            return pageInfoToPageInfoVO(pageInfoPage);
        }
    }


    @Override
    public List<PageInfoRespVO> top10Page() {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String top10Page = ops.get("top10Page");
        if (!StringUtils.isEmpty(top10Page)) {
            log.info("缓存命中，返回缓存中的数据");
            return JSON.parseObject(top10Page, new TypeReference<List<PageInfoRespVO>>() {
            });
        }
        return getTop10Page();

    }


    @Override
    public List<PageInfoRespVO> top10PageByView() {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String top10PageByView = ops.get("top10PageByView");
        if (!StringUtils.isEmpty(top10PageByView)) {
            log.info("缓存命中，返回缓存中的数据");
            return JSON.parseObject(top10PageByView, new TypeReference<List<PageInfoRespVO>>() {
            });
        }
        return getTop10PageByViewPage();
    }

    @Override
    public List<PageNumVo> GetPublishedPagesNumOrderByCategory(Integer userId) {
        List<PageCategory> categoryList = pageCategoryService.list();
        List<PageNumVo> collect = categoryList.stream().map(category -> {
            PageNumVo pageNumVo = new PageNumVo();
            pageNumVo.setCategoryId(category.getCategoryId());
            pageNumVo.setCategoryName(category.getValue());
            List<PageInfo> infoList = null;
            if (userId == null) {
                infoList = baseMapper.selectList(new QueryWrapper<PageInfo>().eq("category_id", category.getCategoryId()).eq("publish_state", PublishStatusEnum.PUBLISHED.getPublishState()));
            }else {
                infoList = baseMapper.selectList(new QueryWrapper<PageInfo>().eq("author_id",userId).eq("category_id", category.getCategoryId()).eq("publish_state", PublishStatusEnum.PUBLISHED.getPublishState()));
            }
            pageNumVo.setPageNum((long) infoList.size());
            return pageNumVo;
        }).collect(Collectors.toList());
        return collect;
    }

    private List<PageInfoRespVO> getTop10Page() {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        UUID uuid = UUID.randomUUID();
        List<PageInfoRespVO> records = null;
        Boolean lock = ops.setIfAbsent("top10Page_lock", uuid.toString(), 30, TimeUnit.SECONDS);
        if (lock != null && lock) {
            try {
                QueryWrapper<PageInfo> queryWrapper = new QueryWrapper<>();
                queryWrapper.orderByDesc("star")
                        .apply(true, "TO_DAYS(NOW())-TO_DAYS(publish_time) < 30")
                        .last("limit 10");
                List<PageInfo> list = baseMapper.selectList(queryWrapper);
                Page<PageInfo> infoPage = new Page<>();
                infoPage.setRecords(list);
                records = pageInfoToPageInfoVO(infoPage).getRecords();
                log.info("===向Redis中存入分类数据===");
                ops.setIfAbsent("top10Page", JSON.toJSONString(records), 5, TimeUnit.DAYS);
            } finally {
                redisTemplate.delete("top10Page_lock");
            }
        } else {
            try {
                Thread.sleep(50);
                return top10Page();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return records;
    }

    private List<PageInfoRespVO> getTop10PageByViewPage() {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        UUID uuid = UUID.randomUUID();
        List<PageInfoRespVO> records = null;
        Boolean lock = ops.setIfAbsent("top10PageByView_lock", uuid.toString(), 30, TimeUnit.SECONDS);
        if (lock != null && lock) {
            try {
                QueryWrapper<PageInfo> queryWrapper = new QueryWrapper<>();
                queryWrapper.orderByDesc("view")
                        .apply(true, "TO_DAYS(NOW())-TO_DAYS(publish_time) < 30")
                        .last("limit 10");
                List<PageInfo> list = baseMapper.selectList(queryWrapper);
                Page<PageInfo> infoPage = new Page<>();
                infoPage.setRecords(list);
                records = pageInfoToPageInfoVO(infoPage).getRecords();
                log.info("===向Redis中存入分类数据===");
                ops.setIfAbsent("top10PageByView", JSON.toJSONString(records), 5, TimeUnit.DAYS);
            } finally {
                redisTemplate.delete("top10PageByView_lock");
            }
        } else {
            try {
                Thread.sleep(50);
                return top10PageByView();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return records;
    }
}
